#include "stdafx.h"
#include "resource.h"
#include "microsipDlg.h"
#include "Mmsystem.h"
#include "settings.h"
#include "global.h"
#include "ModelessMessageBox.h"
#include "utf.h"
#include "jumplist.h"

#include <io.h>
#include <afxinet.h>
#include <ws2tcpip.h>

#include <Strsafe.h>

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

static char *g_lpCmdLine="";

CmicrosipDlg *microsipDlg;

static UINT BASED_CODE indicators[] =
{
	ID_STATUSBAR
};

static bool timerContactBlinkState = false;
static bool beepPlaying = false;


CmicrosipDlg::~CmicrosipDlg(void)
{
	//KillTimer(IDT_TIMER_0);
}

void CmicrosipDlg::PostNcDestroy()
{
	CBaseDialog::PostNcDestroy();
	RemoveJumpList();
	if (tnd.hWnd) {
		Shell_NotifyIcon(NIM_DELETE, &tnd);
	}
	PJDestroy();
	UnloadLangPackModule();
	delete this;
}

void CmicrosipDlg::DoDataExchange(CDataExchange* pDX)
{
	CBaseDialog::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CmicrosipDlg, CBaseDialog)
	ON_WM_SYSCOMMAND()
	ON_WM_QUERYENDSESSION()
	ON_WM_TIMER()
	ON_WM_MOVE()
	ON_WM_SIZE()
	ON_WM_CLOSE()
	ON_WM_CONTEXTMENU()
	ON_MESSAGE(MYWM_NOTIFYICON,onTrayNotify)
	ON_MESSAGE(MYWM_CREATE_RINGING,onCreateRingingDlg)
	ON_MESSAGE(MYWM_DESTROY_RINGING,onDestroyRingingDlg)
	ON_MESSAGE(MYWM_ON_ACCOUNT,OnAccount)
	ON_MESSAGE(MYWM_ON_CALL_MEDIA_STATE,onCallMediaState)
#ifndef _GLOBAL_NO_MESSAGING
	ON_MESSAGE(MYWM_ON_PAGER,onPager)
	ON_MESSAGE(MYWM_ON_PAGER_STATUS,onPagerStatus)
#endif
#ifndef _GLOBAL_NO_CONTACTS
	ON_MESSAGE(MYWM_ON_BUDDY_STATE,onBuddyState)
#endif
	ON_MESSAGE(MYWM_SHELL_EXECUTE,onShellExecute)
	ON_MESSAGE(WM_POWERBROADCAST,onPowerBroadcast)
	ON_MESSAGE(WM_COPYDATA,onDialNumber)
	ON_MESSAGE(MYWM_CALL_ANSWER,onCallAnswer)
	ON_MESSAGE(MYWM_CALL_HANGUP,onCallHangup)
	ON_MESSAGE(MYWM_SET_PANE_TEXT,onSetPaneText)
	ON_COMMAND(ID_ACCOUNT,OnMenuAccount)
	ON_COMMAND(ID_SETTINGS,OnMenuSettings)
	ON_COMMAND(ID_ALWAYS_ON_TOP,OnMenuAlwaysOnTop)
#ifndef _GLOBAL_NO_LOG
	ON_COMMAND(ID_LOG,OnMenuLog)
#endif
	ON_COMMAND(ID_EXIT,OnMenuExit)
	ON_NOTIFY(TCN_SELCHANGE, ID_TAB, &CmicrosipDlg::OnTcnSelchangeTab)
	ON_NOTIFY(TCN_SELCHANGING, ID_TAB, &CmicrosipDlg::OnTcnSelchangingTab)
	ON_COMMAND(ID_WEBSITE,OnMenuWebsite)
#ifdef _GLOBAL_VIDEO
#endif
END_MESSAGE_MAP()


// CmicrosipDlg message handlers

CmicrosipDlg::CmicrosipDlg(CWnd* pParent /*=NULL*/)
: CBaseDialog(CmicrosipDlg::IDD, pParent)
{
	this->m_hWnd = NULL;
	microsipDlg = this;
	Create (IDD, pParent);
}

BOOL CmicrosipDlg::OnInitDialog()
{
	AFX_MANAGE_STATE(AfxGetStaticModuleState());

	CBaseDialog::OnInitDialog();
	if ( strcmp(g_lpCmdLine,"/hidden") == 0) {
		accountSettings.hidden = TRUE;
		g_lpCmdLine = "";
	}

	LoadLangPackModule();

	callTimer = 0;

#ifndef _GLOBAL_NO_ACCOUNT
	accountDlg = NULL;
#endif
#ifndef _GLOBAL_NO_SETTINGS
	settingsDlg = NULL;
#endif
	messagesDlg = new MessagesDlg(this);
	transferDlg = NULL;

#ifdef _GLOBAL_ACCOUNT_REG
	reg1Dlg = NULL;
	reg2Dlg = NULL;
	reg3Dlg = NULL;
	regUserId = 0;
#endif
#ifdef _GLOBAL_CONFERENCE_DIALOG
	conferenceDlg = NULL;
#endif

	m_idleCounter = 0;
	m_isAway = FALSE;

#ifdef _GLOBAL_VIDEO
	previewWin = NULL;
#endif

	SetTimer(IDT_TIMER_0,5000,NULL);

	if (!accountSettings.hidden) {

		SetupJumpList();

		m_hIcon = ::LoadIcon(AfxGetInstanceHandle(),MAKEINTRESOURCE(IDR_MAINFRAME));
		iconSmall = (HICON)LoadImage(
			AfxGetInstanceHandle(),
			MAKEINTRESOURCE(IDR_MAINFRAME),
			IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), LR_SHARED );
		PostMessage(WM_SETICON,ICON_SMALL,(LPARAM)iconSmall);

		TranslateDialog(this->m_hWnd);

		// Set the icon for this dialog.  The framework does this automatically
		//  when the application's main window is not a dialog
		SetIcon(m_hIcon, TRUE);			// Set big icon
		SetIcon(m_hIcon, FALSE);		// Set small icon

		// TODO: Add extra initialization here

		// add tray icon
		CString str;
#ifndef _GLOBAL_TRAY_HINT
		str.Format("%s %s", Translate(_GLOBAL_NAME_NICE), _GLOBAL_VERSION);
#else
		str = _GLOBAL_TRAY_HINT;
#endif
		tnd.cbSize = NOTIFYICONDATA_V3_SIZE;
		tnd.hWnd = this->GetSafeHwnd();
		tnd.uID = IDR_MAINFRAME;
		tnd.uCallbackMessage = MYWM_NOTIFYICON;
		tnd.uFlags = NIF_MESSAGE|NIF_ICON|NIF_TIP; 
#if !defined _GLOBAL_CUSTOM || defined _GLOBAL_ICON_INACTIVE
		iconInactive = LoadIcon(AfxGetInstanceHandle(),MAKEINTRESOURCE(IDI_INACTIVE));
		tnd.hIcon = iconInactive;
#else 
		tnd.hIcon = iconSmall;
#endif
		lstrcpyn(tnd.szTip, (LPCTSTR)str, sizeof(tnd.szTip));
		DWORD dwMessage = NIM_ADD;
		Shell_NotifyIcon(dwMessage, &tnd);
	} else {
		tnd.hWnd = NULL;
	}

	m_bar.Create(this);
	m_bar.SetIndicators(indicators,1);
	m_bar.SetPaneInfo(0,ID_STATUSBAR, SBPS_STRETCH , 0);
	RepositionBars(AFX_IDW_CONTROLBAR_FIRST, AFX_IDW_CONTROLBAR_LAST, ID_STATUSBAR);

	m_bar.SetPaneText( 0, "");

	AutoMove(ID_TAB,0,0,100,0);
	AutoMove(m_bar.m_hWnd,0,100,100,0);

	//--set window pos
	CRect screenRect;
	screenRect.left = GetSystemMetrics (SM_XVIRTUALSCREEN);
	screenRect.top = GetSystemMetrics (SM_YVIRTUALSCREEN);
	screenRect.right = GetSystemMetrics (SM_CXVIRTUALSCREEN) - screenRect.left;
	screenRect.bottom = GetSystemMetrics (SM_CYVIRTUALSCREEN) - screenRect.top;

	CRect rect;
	GetWindowRect(&rect);
	int mx;
	int my;
#ifndef _GLOBAL_WIDTH
	//int mW = accountSettings.mainW>0?accountSettings.mainW:325;
	int mW = accountSettings.mainW>0?accountSettings.mainW:rect.Width();
#else
	int mW = accountSettings.mainW>0?accountSettings.mainW:_GLOBAL_WIDTH;
#endif
	int mH = accountSettings.mainH>0?accountSettings.mainH:rect.Height();
	// coors not specified, first run
	if (!accountSettings.mainX && !accountSettings.mainY) {
		CRect primaryScreenRect;
		SystemParametersInfo(SPI_GETWORKAREA,0,&primaryScreenRect,0);
		mx = primaryScreenRect.Width()-mW;
		my = primaryScreenRect.Height()-mH;
	} else {
		int maxLeft = screenRect.right-mW;
		if (accountSettings.mainX>maxLeft) {
			mx = maxLeft;
		} else {
			mx = accountSettings.mainX < screenRect.left ? screenRect.left : accountSettings.mainX;
		}
		int maxTop = screenRect.bottom-mH;
		if (accountSettings.mainY>maxTop) {
			my = maxTop;
		} else {
			my = accountSettings.mainY < screenRect.top ? screenRect.top : accountSettings.mainY;
		}
	}

	//--set messages window pos/size
	messagesDlg->GetWindowRect(&rect);
	int messagesX;
	int messagesY;
	int messagesW = accountSettings.messagesW>0?accountSettings.messagesW:550;
	int messagesH = accountSettings.messagesH>0?accountSettings.messagesH:mH;
	// coors not specified, first run
	if (!accountSettings.messagesX && !accountSettings.messagesY) {
		accountSettings.messagesX = mx - messagesW;
		accountSettings.messagesY = my;
	}
	int maxLeft = screenRect.right-messagesW;
	if (accountSettings.messagesX>maxLeft) {
		messagesX = maxLeft;
	} else {
		messagesX = accountSettings.messagesX < screenRect.left ? screenRect.left : accountSettings.messagesX;
	}
	int maxTop = screenRect.bottom-messagesH;
	if (accountSettings.messagesY>maxTop) {
		messagesY = maxTop;
	} else {
		messagesY = accountSettings.messagesY < screenRect.top ? screenRect.top : accountSettings.messagesY;
	}

	messagesDlg->SetWindowPos(NULL, messagesX, messagesY, messagesW, messagesH, SWP_NOZORDER);
	SetWindowPos(accountSettings.alwaysOnTop?&CWnd::wndTopMost:&CWnd::wndNoTopMost, mx, my, mW, mH, NULL);

	CTabCtrl* tab = (CTabCtrl*) GetDlgItem(ID_TAB);
	tab->SetMinTabWidth(1);
	TC_ITEM tabItem;
	tabItem.mask = TCIF_TEXT | TCIF_PARAM;

	pageDialer = new Dialer(this);
	tabItem.pszText = Translate("Dialpad");
	tabItem.lParam = (LPARAM)pageDialer;
	tab->InsertItem( 0, &tabItem );

#ifdef _GLOBAL_PADDING_TOP
	pageDialer->SetWindowPos(NULL, 0, 32, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
#else
	pageDialer->SetWindowPos(NULL, 0, 32, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
#endif

	AutoMove(pageDialer->m_hWnd,50,50,0,0);

	pageCalls = new Calls(this);
	tabItem.pszText = Translate("Calls");
	tabItem.lParam = (LPARAM)pageCalls;
	tab->InsertItem( 1, &tabItem );
	pageCalls->SetWindowPos(NULL, 0, 32, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
	AutoMove(pageCalls->m_hWnd,0,0,100,100);

#ifndef _GLOBAL_NO_CONTACTS
	pageContacts = new Contacts(this);
	tabItem.pszText = Translate("Contacts");
	tabItem.lParam = (LPARAM)pageContacts;
	tab->InsertItem( 2, &tabItem );
	pageContacts->SetWindowPos(NULL, 0, 32, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
	AutoMove(pageContacts->m_hWnd,0,0,100,100);
#endif

#ifdef _GLOBAL_TAB_ACCOUNT
	tabItem.pszText = "$";
	tab->InsertItem( 3, &tabItem );
#endif
#ifdef _GLOBAL_TAB_HELP
	tabItem.pszText = "?";
	tab->InsertItem( 4, &tabItem );
#endif


#ifdef _GLOBAL_PAGE_BUTTONS
	pageButtons = new Buttons(this);
	tabItem.pszText = Translate("Language");
	tabItem.lParam = (LPARAM)pageButtons;
	tab->InsertItem( 2, &tabItem );
	pageButtons->SetWindowPos(NULL, 0, 32, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
	AutoMove(pageButtons->m_hWnd,50,50,0,0);
#endif

	switch (accountSettings.activeTab)
	{
#ifndef _GLOBAL_NO_CONTACTS
	case 1:
		pageCalls->ShowWindow( SW_SHOW );
		tab->SetCurSel(1);
		break;
	case 2:
		pageContacts->ShowWindow( SW_SHOW );
		tab->SetCurSel(2);
		break;
#else
	case 1:
		pageCalls->ShowWindow( SW_SHOW );
		tab->SetCurSel(1);
		break;
#ifdef _GLOBAL_PAGE_BUTTONS
	case 2:
		pageButtons->ShowWindow( SW_SHOW );
		tab->SetCurSel(2);
		break;
#endif
#endif
	default:
		pageDialer->ShowWindow( SW_SHOW );
		tab->SetCurSel(0);
	}

	BOOL minimized = !strcmp(g_lpCmdLine, "/minimized");
	if (minimized) {
		g_lpCmdLine = "";
	}
	if ( firstRun || !minimized) {
		onTrayNotify(NULL,WM_LBUTTONUP);
	}

#ifdef _GLOBAL_NO_AUTO_REGISTER
	disableAutoRegister = TRUE;
#else
	disableAutoRegister = FALSE;
#endif

	SetTimer(IDT_TIMER_INIT,100,NULL);

	return TRUE;  // return TRUE  unless you set the focus to a control
}


void CmicrosipDlg::BaloonPopup(CString title, CString message, DWORD flags)
{
	if (tnd.hWnd) {
		lstrcpyn(tnd.szInfo, message, sizeof(tnd.szInfo));
		lstrcpyn(tnd.szInfoTitle, title, sizeof(tnd.szInfoTitle));
		tnd.uFlags = tnd.uFlags | NIF_INFO; 
		tnd.dwInfoFlags = flags;
		DWORD dwMessage = NIM_MODIFY;
		Shell_NotifyIcon(dwMessage, &tnd);
	}
}

void CmicrosipDlg::OnMenuAccount()
{
#ifndef _GLOBAL_NO_ACCOUNT
	if (!accountSettings.hidden) {
		if (!accountDlg)
		{
			accountDlg = new AccountDlg(this);
		} else {
			accountDlg->SetForegroundWindow();
		}
	}
#endif
}

void CmicrosipDlg::OnMenuSettings()
{
#ifndef _GLOBAL_NO_SETTINGS
	if (!accountSettings.hidden) {
		if (!settingsDlg)
		{
			settingsDlg = new SettingsDlg(this);
		} else {
			settingsDlg->SetForegroundWindow();
		}
	}
#endif
}

void CmicrosipDlg::OnMenuAlwaysOnTop()
{
	accountSettings.alwaysOnTop = 1 - accountSettings.alwaysOnTop;
	accountSettings.Save();
	SetWindowPos(accountSettings.alwaysOnTop?&this->wndTopMost:&this->wndNoTopMost,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE);
}

#ifndef _GLOBAL_NO_LOG
void CmicrosipDlg::OnMenuLog()
{
	ShellExecute(NULL, NULL, accountSettings.logFile, NULL, NULL, SW_SHOWNORMAL);
}
#endif

void CmicrosipDlg::OnMenuExit()
{
	DestroyWindow ();
}

LRESULT CmicrosipDlg::onTrayNotify(WPARAM wParam,LPARAM lParam)
{
	UINT uMsg = (UINT) lParam; 
	switch (uMsg ) 
	{ 
	case WM_LBUTTONUP:
		if (this->IsWindowVisible() && !IsIconic())
		{
			if (wParam) {
				this->ShowWindow(SW_HIDE);
			} else {
				SetForegroundWindow();
			}
		} else
		{
			if (!accountSettings.hidden) {
				if (IsIconic()) {
					ShowWindow(SW_RESTORE);
				} else {
					ShowWindow(SW_SHOW);
				}
				SetForegroundWindow();
				CTabCtrl* tab = (CTabCtrl*) GetDlgItem(ID_TAB);
				int nTab = tab->GetCurSel();
				TC_ITEM tci;
				tci.mask = TCIF_PARAM;
				tab->GetItem(nTab, &tci);
				CWnd* pWnd = (CWnd *)tci.lParam;
				pWnd->SetFocus();
			}
		}
		break;
	case WM_RBUTTONUP:
		MainPopupMenu();
		break;
	} 
	return TRUE;
}

void CmicrosipDlg::MainPopupMenu() 
{
	CPoint point;    
	GetCursorPos(&point);
	CMenu menu;
	menu.LoadMenu(IDR_MENU_TRAY);
	CMenu* tracker = menu.GetSubMenu(0);
	TranslateMenu(tracker->m_hMenu);
	if (!accountSettings.enableLog) {
		tracker->EnableMenuItem(ID_LOG, MF_DISABLED | MF_GRAYED);
	}
	if (accountSettings.alwaysOnTop) {
		tracker->CheckMenuItem(ID_ALWAYS_ON_TOP,MF_CHECKED);
	}
	SetForegroundWindow();
	tracker->TrackPopupMenu( 0, point.x, point.y, this );
	PostMessage(WM_NULL, 0, 0);
}

LRESULT CmicrosipDlg::onCreateRingingDlg(WPARAM wParam,LPARAM lParam)
{
	pjsua_call_info* call_info = (pjsua_call_info*) wParam;
	pjsip_rx_data *rdata = (pjsip_rx_data*) lParam;

	RinginDlg* ringinDlg = new RinginDlg(this);

	if (call_info->rem_vid_cnt) {
		((CButton*)ringinDlg->GetDlgItem(IDC_VIDEO))->EnableWindow(TRUE);
	}
	ringinDlg->GotoDlgCtrl(ringinDlg->GetDlgItem(IDC_CALLER_NAME));

	ringinDlg->call_id = call_info->id;
	SIPURI sipuri;
	CStringW rab;
	CString str;
	CString info;

	info = PjToStr(&call_info->remote_info, TRUE);
	ParseSIPURI(info, &sipuri);
#ifndef _GLOBAL_NO_CONTACTS
	CString name = pageContacts->GetNameByNumber(GetSIPURI(sipuri.user, true));
#else
	CString name;
#endif
	if (name == "") {
		name = sipuri.name!="" ? sipuri.name : (sipuri.user!=""?sipuri.user:sipuri.domain);
	}
	ringinDlg->GetDlgItem(IDC_CALLER_NAME)->SetWindowText(name);

#ifndef _GLOBAL_ACCOUNT_MINI
	int c = 0;
	int len=0;

	info=(sipuri.user!=""?sipuri.user+"@":"")+sipuri.domain;
	if (sipuri.name!="" && sipuri.name!=name) {
		info = sipuri.name + " <" + info + ">";
	}
	len+=info.GetLength();
	str.Format("%s\r\n\r\n", info);

	info = PjToStr(&call_info->local_info, TRUE);
	ParseSIPURI(info, &sipuri);
	info=(sipuri.user!=""?sipuri.user+"@":"")+sipuri.domain;
	len+=info.GetLength();
	str.AppendFormat("%s: %s\r\n\r\n", Translate("To"), info);

	if (len<70) {
		c++;
	}

	pjsip_generic_string_hdr *hsr = NULL;
	const pj_str_t header = {"User-Agent",10};
	hsr = (pjsip_generic_string_hdr*) pjsip_msg_find_hdr_by_name ( rdata->msg_info.msg, &header, NULL);
	if (hsr) {
		str.AppendFormat("%s: %s", Translate("User-Agent"), PjToStr(&hsr->hvalue, TRUE));
	} else {
		c++;
	}

	for (int i=0; i<c; i++) {
		str = "\r\n" + str;
	}

	
#else
	str = sipuri.user!=""?sipuri.user:sipuri.domain;
#endif
	if (str != name) {
		ringinDlg->GetDlgItem(IDC_CALLER_ADDR)->SetWindowText(str);
	} else {
		ringinDlg->GetDlgItem(IDC_CALLER_ADDR)->EnableWindow(FALSE);
	}
	ringinDlgs.Add(ringinDlg);
	return 0;
}

LRESULT CmicrosipDlg::onDestroyRingingDlg(WPARAM wParam,LPARAM lParam)
{
	RinginDlg *ringinDlg = (RinginDlg *)wParam;
	ringinDlg->DestroyWindow();
	return 0;
}


LRESULT CmicrosipDlg::onCallMediaState(WPARAM wParam,LPARAM lParam) {
	pjsua_call_info *call_info = (pjsua_call_info *) wParam;

	messagesDlg->UpdateHoldButton(call_info);

	CString message;
	CString number = PjToStr(&call_info->remote_info, TRUE);

	MessagesContact* messagesContact = messagesDlg->AddTab(number, "", FALSE, call_info, TRUE, TRUE);

	if (messagesContact) {
		if (call_info->media_status == PJSUA_CALL_MEDIA_REMOTE_HOLD) {
			message = "Call on remote hold";
		}
		if (call_info->media_status == PJSUA_CALL_MEDIA_LOCAL_HOLD) {
			message = "Call on local hold";
		}
		if (call_info->media_status == PJSUA_CALL_MEDIA_NONE) {
			message = "Call on hold";
		}
		if (messagesContact->mediaStatus != PJSUA_CALL_MEDIA_ERROR && messagesContact->mediaStatus != call_info->media_status && call_info->media_status == PJSUA_CALL_MEDIA_ACTIVE) {
			message = "Call is active";
		}
		if (message!="") {
			messagesDlg->AddMessage(messagesContact, Translate(message.GetBuffer()), MSIP_MESSAGE_TYPE_SYSTEM, TRUE);
		}
		messagesContact->mediaStatus = call_info->media_status;
	}
	return 0;
}

#ifndef _GLOBAL_NO_MESSAGING
LRESULT CmicrosipDlg::onPager(WPARAM wParam,LPARAM lParam)
{
	pj_str_t *from = (pj_str_t *)wParam;
	pj_str_t *body = (pj_str_t *)lParam;
	CString number=PjToStr(from, TRUE);
	CString message=PjToStr(body, TRUE);
	message.Trim();
	MessagesContact* messagesContact = messagesDlg->AddTab(number);
	if (messagesContact) {
		messagesDlg->AddMessage(messagesContact, message, MSIP_MESSAGE_TYPE_REMOTE);
	}
	return 0;
}

LRESULT CmicrosipDlg::onPagerStatus(WPARAM wParam,LPARAM lParam)
{
	pj_str_t *to = (pj_str_t *)wParam;
	pj_str_t *reason = (pj_str_t *)lParam;
	CString number=PjToStr(to, TRUE);
	CString message=PjToStr(reason);
	message.Trim();
	MessagesContact* messagesContact = microsipDlg->messagesDlg->AddTab(number);
	if (messagesContact) {
		microsipDlg->messagesDlg->AddMessage(messagesContact, message);
	}
	return 0;
}
#endif

#ifndef _GLOBAL_NO_CONTACTS
LRESULT CmicrosipDlg::onBuddyState(WPARAM wParam,LPARAM lParam)
{
	Contact *contact = (Contact *)wParam;
	CListCtrl *list= (CListCtrl*)pageContacts->GetDlgItem(IDC_CONTACTS);
	int n = list->GetItemCount();
	for (int i=0; i<n; i++) {
		if (contact==(Contact *)list->GetItemData(i)) {
			list->SetItem(i, 0, LVIF_IMAGE, 0, contact->image, 0, 0, 0);
		}
	}
	if (contact->ringing) {
		SetTimer(IDT_TIMER_CONTACTS_BLINK,500,NULL);
		OnTimerContactBlink();
	}
	return 0;
}
#endif

LRESULT CmicrosipDlg::onShellExecute(WPARAM wParam,LPARAM lParam)
{
	ShellExecute(NULL, NULL, (LPTSTR)wParam, (LPTSTR)lParam, NULL, SW_HIDE);
	return 0;
}

LRESULT CmicrosipDlg::onPowerBroadcast(WPARAM wParam,LPARAM lParam)
{
	if (wParam == PBT_APMRESUMEAUTOMATIC)
	{
		BOOL err = TRUE; 	
		int nCount = 0;
		WSADATA wsaData;
		int wsaError = -1;
		while (err && nCount < 3) {
			err = FALSE;
			if (wsaError) {
				wsaError = WSAStartup(MAKEWORD(2,2), &wsaData);
				if (wsaError==WSASYSNOTREADY) {
					err = TRUE;
				} else if (wsaError) {
					break;
				}
			}
			if (!err) {
				char buf[256]={0};
				if ( gethostname(buf, 256) != 0) {
					err = TRUE;
				}
				else {
					struct addrinfo* l_addrInfo = NULL;
					struct addrinfo l_addrInfoHints;
					ZeroMemory(&l_addrInfoHints, sizeof(addrinfo));
					l_addrInfoHints.ai_socktype = SOCK_STREAM;
					l_addrInfoHints.ai_family = PF_INET;
					if ( getaddrinfo(buf,NULL, &l_addrInfoHints,&l_addrInfo) == 0 ) {
						if (l_addrInfo) {
							struct sockaddr_in *ipv4 = (struct sockaddr_in *)l_addrInfo->ai_addr;
							char * ip = inet_ntoa(ipv4->sin_addr);
							if ( !strcmp(ip, "127.0.0.1") )
							{
								err = TRUE;
#ifdef _GLOBAL_LOCAL_SIP_SERVER
							} else {
								accountSettings.server = ip;
								accountSettings.domain = ip;
#endif
							}
						} else {
							err = TRUE;
						}
					} else {
						err = TRUE;
					}
				}
			}
			if (err) {
				Sleep(3000);
				nCount++;
			}
		}
		WSACleanup();

		PJCreate();
		PJAccountAdd();
	} else if (wParam == PBT_APMSUSPEND)
	{
		PJDestroy();
	}
	return TRUE;
}

LRESULT CmicrosipDlg::OnAccount(WPARAM wParam,LPARAM lParam)
{
#ifndef _GLOBAL_NO_ACCOUNT
	OnMenuAccount();
	if (wParam && accountDlg) {
		CEdit *edit = (CEdit*)accountDlg->GetDlgItem(IDC_EDIT_PASSWORD);
		if (edit) {
			edit->SetFocus();
			int nLength = edit->GetWindowTextLength();
			edit->SetSel(nLength,nLength);
		}
	}
#endif
	return 0;
}

void CmicrosipDlg::OnTimerCall (bool manual)
{
	int duration = !manual ? messagesDlg->GetCallDuration() : 0;
	if (duration!=-1) {
		CString str;
		str.Format("%s %s",Translate("Connected"), GetDuration(duration, true));
		UpdateWindowText(str, IDI_ACTIVE);
	} else {
		if (KillTimer(IDT_TIMER_CALL)) {
			callTimer = 0;
		}
	}
}

#ifndef _GLOBAL_NO_CONTACTS
void CmicrosipDlg::OnTimerContactBlink ()
{
	CListCtrl *list= (CListCtrl*)pageContacts->GetDlgItem(IDC_CONTACTS);
	int n = list->GetItemCount();
	bool ringing = false;
	for (int i=0; i<n; i++) {
		Contact *contact = (Contact *)list->GetItemData(i);
		if (contact->ringing) {
			list->SetItem(i, 0, LVIF_IMAGE, 0, timerContactBlinkState?5:contact->image, 0, 0, 0);
			ringing = true;
		} else {
			list->SetItem(i, 0, LVIF_IMAGE, 0, contact->image, 0, 0, 0);
		}
	}
	if (!ringing) {
		KillTimer(IDT_TIMER_CONTACTS_BLINK);
		timerContactBlinkState=false;
	} else {
		timerContactBlinkState = !timerContactBlinkState;
	}
}
#endif

void CmicrosipDlg::OnTimer (UINT TimerVal)
{
	if (TimerVal == IDT_TIMER_DIRECTORY) {
		UsersDirectoryLoad();
	} else if (TimerVal == IDT_TIMER_CONTACTS_BLINK) {
#ifndef _GLOBAL_NO_CONTACTS
		OnTimerContactBlink();
#endif
	} else if (TimerVal == IDT_TIMER_CALL) {
		OnTimerCall();
	} else
#if defined _GLOBAL_BALANCE || defined _GLOBAL_BALANCE_GTN || defined _GLOBAL_BALANCE_PLAIN || defined _GLOBAL_BALANCE_OPTIONS
		if (TimerVal == IDT_TIMER_BALANCE)
		{
			KillTimer(IDT_TIMER_BALANCE);
#ifdef _GLOBAL_BALANCE_OPTIONS
			BalanceOption();
#else
#ifdef _GLOBAL_BALANCE_PLAIN
			BalancePlain();
#else
#ifdef _GLOBAL_BALANCE_GTN
			BalanceGTN();
#else
#ifdef _GLOBAL_BALANCE_BEE
			microsipDlg->BalanceBEE();
#else
			pjsua_acc_set_registration(account, TRUE);
#endif
#endif
#endif
#endif
		} else
#endif
			if (TimerVal == IDT_TIMER_INIT)
			{
				KillTimer(IDT_TIMER_INIT);
#ifdef _GLOBAL_ACCOUNT_MINI
				if (
#ifndef _GLOBAL_NO_AUTO_REGISTER
#ifndef _GLOBAL_API
					accountSettings.username==""
#else
					accountSettings.apiLogin==""
#endif
#else
					1
#endif
					)
				{
					OnMenuAccount();
				}
#endif
#ifdef _GLOBAL_CONFERENCE_DIALOG
				conferenceDlg = new ConferenceDlg(this);
#endif
				onPowerBroadcast(PBT_APMRESUMEAUTOMATIC, NULL);
			} else
				if (TimerVal == IDT_TIMER_0)
				{
					POINT coord;
					GetCursorPos(&coord);
					if (m_mousePos.x != coord.x || m_mousePos.y != coord.y)
					{
						m_idleCounter = 0;
						m_mousePos = coord;
						if (m_isAway)
						{
							PublishStatus();
						}
					} else {
						m_idleCounter++;
						if (m_idleCounter == 120)
						{
							PublishStatus(FALSE);
						}
					}
				} else 
				{
					microsipDlg->RingIn("ringout.wav", TRUE, TRUE);
				}
}


void CmicrosipDlg::PJAccountAdd()
{
	pjsua_acc_config acc_cfg;
	pj_status_t status;

	transport = MSIP_TRANSPORT_AUTO;
	account = -1;
#ifdef _GLOBAL_ACCOUNT_REG
	regUserId = 0;
#endif

	BOOL isLocal = accountSettings.username=="" || accountSettings.domain=="";

	CString title = Translate(_GLOBAL_NAME_NICE);
#ifndef _GLOBAL_ACCOUNT_PIN
	CString usernameLocal;
#ifndef _GLOBAL_API
	usernameLocal = accountSettings.username;
#else
	usernameLocal = accountSettings.apiLogin;
#endif
	if (!disableAutoRegister) {
		if (accountSettings.displayName!="")
		{
			title.Append( " - " + accountSettings.displayName);
		} else if (usernameLocal.GetLength())
		{
			title.Append( " - " + usernameLocal);
		}
	}
#endif
	SetWindowText(title);

	pjsua_acc_config_default(&acc_cfg);
	acc_cfg.rtp_cfg.public_addr = pj_str( accountSettings.publicAddr.GetBuffer() );

	acc_cfg.allow_via_rewrite=accountSettings.allowRewrite ? PJ_TRUE : PJ_FALSE;
	acc_cfg.allow_sdp_nat_rewrite=acc_cfg.allow_via_rewrite;
	acc_cfg.allow_contact_rewrite=acc_cfg.allow_via_rewrite ? 2 : PJ_FALSE;
	
	acc_cfg.publish_enabled = accountSettings.publish ? PJ_TRUE : PJ_FALSE;
#ifdef _GLOBAL_KEEPALIVE_UDP
	acc_cfg.ka_interval = _GLOBAL_KEEPALIVE_UDP;
#endif

#ifdef _GLOBAL_VIDEO
	acc_cfg.vid_in_auto_show = PJ_TRUE;
	acc_cfg.vid_out_auto_transmit = PJ_TRUE;
	acc_cfg.vid_cap_dev = VideoCaptureDeviceId();
	acc_cfg.vid_wnd_flags = PJMEDIA_VID_DEV_WND_BORDER | PJMEDIA_VID_DEV_WND_RESIZABLE;
#endif

#ifdef _GLOBAL_DSCP_MEDIA
	acc_cfg.rtp_cfg.qos_params.flags = PJ_QOS_PARAM_HAS_DSCP;
	acc_cfg.rtp_cfg.qos_params.dscp_val = _GLOBAL_DSCP_MEDIA;
#endif

	if (accountSettings.transport=="udp" && transport_udp!=-1) {
		acc_cfg.transport_id = transport_udp;
	} else if (accountSettings.transport=="tcp" && transport_tcp!=-1) {
		transport = MSIP_TRANSPORT_TCP;
	} else if (accountSettings.transport=="tls" && transport_tls!=-1) {
		transport = MSIP_TRANSPORT_TLS;
	}

	if (isLocal || !accountSettings.disableLocalAccount)
	{
		pjsua_acc_id acc_id;
		//pjsua_acc_add_local(NULL, PJ_TRUE, &acc_id);
		acc_cfg.priority--;
		pjsua_transport_data *t = &pjsua_var.tpdata[0];

		CString localURI;
		if (accountSettings.displayName!="")
		{
			localURI = "\"" + accountSettings.displayName + "\" ";
		}
		localURI.AppendFormat("<sip:%s>", PjToStr(&t->local_name.host));
		
		acc_cfg.id = pj_str(StrToPj(localURI));

		pjsua_acc_add(&acc_cfg, PJ_TRUE, &acc_id);
		acc_cfg.priority++;
	}

	if (disableAutoRegister) {
		isLocal = TRUE;
		disableAutoRegister = FALSE;
	}

	if (!isLocal)
	{
		CString str;
		str.Format("%s...",Translate("Connecting"));
		UpdateWindowText(str);

		CString proxy;
		if (accountSettings.domain!="" && accountSettings.proxy!="")
		{
			acc_cfg.proxy_cnt = 1;
			proxy.Format("sip:%s",accountSettings.proxy);
			AddTransportSuffix(proxy);
			acc_cfg.proxy[0] = pj_str( proxy.GetBuffer() );
		}

		CString localURI;
		if (accountSettings.displayName!="")
		{
			localURI = "\"" + accountSettings.displayName + "\" ";
		}
#ifdef _GLOBAL_USERNAME_SUFFIX
		localURI += GetSIPURI(accountSettings.username + _GLOBAL_USERNAME_SUFFIX);
#else
		localURI += GetSIPURI(accountSettings.username);
#endif
		acc_cfg.id = pj_str(StrToPj(localURI));
		acc_cfg.cred_count = 1;
#ifdef _GLOBAL_USERNAME_SUFFIX
		CString username;
		if (accountSettings.authID!="") {
			username = accountSettings.authID;
		} else {
			username = accountSettings.username + _GLOBAL_USERNAME_SUFFIX;
		}
		acc_cfg.cred_info[0].username = pj_str( username.GetBuffer() );
#else
		acc_cfg.cred_info[0].username = pj_str( accountSettings.authID!=""? accountSettings.authID.GetBuffer() : accountSettings.username.GetBuffer() );
#endif
		acc_cfg.cred_info[0].realm = pj_str("*");
		acc_cfg.cred_info[0].scheme = pj_str("Digest");
		acc_cfg.cred_info[0].data_type = PJSIP_CRED_DATA_PLAIN_PASSWD;
		acc_cfg.cred_info[0].data = pj_str( accountSettings.password.GetBuffer() );

		CString regURI;
		if (accountSettings.server=="") {
			acc_cfg.register_on_acc_add = PJ_FALSE;
		} else {
			regURI.Format("sip:%s",accountSettings.server);
			AddTransportSuffix(regURI);
			acc_cfg.reg_uri = pj_str( regURI.GetBuffer() );
		}

		status = pjsua_acc_add(&acc_cfg, PJ_TRUE, &account);

		if (status == PJ_SUCCESS)
		{
			PublishStatus();
		} else
		{
			ShowErrorMessage(status);
			UpdateWindowText();
		}
	} else
	{
		UpdateWindowText();
	}

	if (strlen(g_lpCmdLine))
	{
		if (!isLocal)
		{
			dialNumberDelayed = g_lpCmdLine;
		} else 
		{
			DialNumber(g_lpCmdLine);
		}
		g_lpCmdLine = "";
	}
}

void CmicrosipDlg::OnTcnSelchangeTab(NMHDR *pNMHDR, LRESULT *pResult)
{
	CTabCtrl* tab = (CTabCtrl*) GetDlgItem(ID_TAB);
	int nTab = tab->GetCurSel();
	TC_ITEM tci;
	tci.mask = TCIF_PARAM;
	tab->GetItem(nTab, &tci);
	CWnd* pWnd = (CWnd *)tci.lParam;
	pWnd->ShowWindow(SW_SHOW);
	pWnd->SetFocus();
	accountSettings.activeTab=nTab;
	accountSettings.Save();
	*pResult = 0;
}

void CmicrosipDlg::OnTcnSelchangingTab(NMHDR *pNMHDR, LRESULT *pResult)
{
	CTabCtrl* tab = (CTabCtrl*) GetDlgItem(ID_TAB);
#if defined _GLOBAL_TAB_ACCOUNT || defined _GLOBAL_TAB_HELP
	TCHITTESTINFO ti;
	GetCursorPos(&ti.pt);
	tab->ScreenToClient(&ti.pt);
	int ind =  tab->HitTest(&ti);
#ifdef _GLOBAL_TAB_ACCOUNT
	if (ind == 3) {
		OpenURL(_GLOBAL_TAB_ACCOUNT);
		*pResult = TRUE;
		return;
	}
#endif
#ifdef _GLOBAL_TAB_HELP
	if (ind == 4) {
		OpenURL(_GLOBAL_TAB_HELP);
		*pResult = TRUE;
		return;
	}
#endif

#endif
	int nTab = tab->GetCurSel();
	TC_ITEM tci;
	tci.mask = TCIF_PARAM;
	tab->GetItem(nTab, &tci);
	CWnd* pWnd = (CWnd *)tci.lParam;
	pWnd->ShowWindow(SW_HIDE);
	*pResult = FALSE;
}

void CmicrosipDlg::UpdateWindowText(CString text, int icon)
{
	if (text=="" && pjsua_call_get_count()>0) {
		return;
	}
	CString str;
	if (text=="" || text=="-") {
		if (pjsua_acc_is_valid(account))
		{
			pjsua_acc_info info;
			pjsua_acc_get_info(account,&info);
			str = PjToStr(&info.status_text);
			if ( str != "Default status message" ) {
				bool noReg = str=="does not register";
				if (noReg || str=="OK")
				{
					str = Translate(m_isAway ? "Away" : "Online");
#ifndef _GLOBAL_ACCOUNT_SIP_SERVER
					if (noReg) {
						str.AppendFormat(" (%s)", Translate("outgoing"));
					}
#endif
					if (balance!="") {
						str.AppendFormat(" - your balance %s", balance);
					}
					icon = m_isAway ? IDI_AWAY : IDI_ONLINE;
#ifndef _GLOBAL_NO_CONTACTS
					pageContacts->PresenceSubsribe();
#endif
					if (dialNumberDelayed!="")
					{
						DialNumber(dialNumberDelayed);
						dialNumberDelayed="";
					}
				} else if (str == "In Progress") {
					str.Format("%s...",Translate("Connecting"));
				} else if (info.status == 401 || info.status == 403) {
#ifndef _GLOBAL_NO_ACCOUNT
					onTrayNotify(NULL,WM_LBUTTONUP);
					PostMessage(MYWM_ON_ACCOUNT,1);
#endif
					icon = IDI_OFFLINE;
#ifndef _GLOBAL_ACCOUNT_PIN
					str = Translate("Incorrect password");
#else
					str = Translate("Incorrect Pin No");
#endif
				} else {
					str = Translate(str.GetBuffer());
				}
				str = str.GetBuffer();
			} else {
				str.Format( "%s: %d", Translate("Response code"),info.status );
			}
		} else {
#ifndef _GLOBAL_STAUSBAR_CAPTION
			str = Translate(_GLOBAL_NAME_NICE);
#else
			str = Translate(_GLOBAL_STAUSBAR_CAPTION);
#endif
			icon = IDI_DEFAULT;
		}
	} else
	{
		str = text;
	}

	CString* pPaneText = new CString();
	*pPaneText = str;
	PostMessage(MYWM_SET_PANE_TEXT, NULL, (LPARAM)pPaneText);

	if (icon!=-1) {
		HICON hIcon = (HICON)LoadImage(
			AfxGetInstanceHandle(),
			MAKEINTRESOURCE(icon),
			IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), LR_SHARED );
		m_bar.GetStatusBarCtrl().SetIcon(0, hIcon);
		
#if !defined _GLOBAL_CUSTOM || defined _GLOBAL_ICON_INACTIVE
		tnd.uFlags = tnd.uFlags & ~NIF_INFO; 
		if ((accountSettings.domain=="" && !accountSettings.disableLocalAccount) || (icon!=IDI_DEFAULT && icon!=IDI_OFFLINE)) {
			if (tnd.hIcon != iconSmall) {
				tnd.hIcon = iconSmall;
				Shell_NotifyIcon(NIM_MODIFY,&tnd);
			}
		} else {
			if (tnd.hIcon != iconInactive) {
				tnd.hIcon = iconInactive;
				Shell_NotifyIcon(NIM_MODIFY,&tnd);
			}
		}
#endif
	}
}

CString CmicrosipDlg::GetErrorMessage(pj_status_t status)
{
	CString str;
	char *buf = str.GetBuffer(PJ_ERR_MSG_SIZE-1);
	pj_strerror(status, buf, PJ_ERR_MSG_SIZE);
	str.ReleaseBuffer();
	int i = str.Find( '(' );
	if (i!=-1)
	{
		str = str.Left(i-1);
	}
	if (str == "Invalid Request URI") {
		str = "Invalid URI";
	}
	return Translate(str.GetBuffer());
}


BOOL CmicrosipDlg::ShowErrorMessage(pj_status_t status)
{
	if (status!=PJ_SUCCESS)
	{
		AfxMessageBox(GetErrorMessage(status));
		return TRUE;
	} else {
		return FALSE;
	}
}

CString CmicrosipDlg::GetSIPURI(CString str, bool isSimple, bool isLocal)
{
	CString rab = str;
	rab.MakeLower();
	int pos = rab.Find("sip:");
	if (pos==-1)
	{
		str="sip:"+str;
	}
	if (!isLocal) {
		pos = str.Find("@");
		if (accountSettings.domain!="" && pos==-1)
		{
			str.Append("@"+accountSettings.domain);
		}
	}
	if (str.GetAt(str.GetLength()-1)=='>')
	{
		str = str.Left(str.GetLength()-1);
		if (!isSimple) {
			if (!isLocal || accountSettings.domain=="") {
				AddTransportSuffix(str);
			}
		}
		str += ">";
	} else {
		if (!isSimple) {
			if (!isLocal || accountSettings.domain=="") {
				AddTransportSuffix(str);
			}
		}
		str = "<" + str + ">";
	}
	return str;
}


void CmicrosipDlg::AddTransportSuffix(CString &str)
{
	switch (transport)
	{ 
	case MSIP_TRANSPORT_TCP:
		str.Append(";transport=tcp");
		break;
	case MSIP_TRANSPORT_TLS:
		str.Append(";transport=tls");
		break;
	}
}

void CmicrosipDlg::PublishStatus(BOOL online)
{
	if (pjsua_acc_is_valid(account))
	{
		pjrpid_element pr;
		pr.type = PJRPID_ELEMENT_TYPE_PERSON;
		pr.id = pj_str(NULL);
		pr.note = pj_str(NULL);
		pr.note = online ? pj_str("Idle") : pj_str("Away");
		pr.activity = online ? PJRPID_ACTIVITY_UNKNOWN : PJRPID_ACTIVITY_AWAY;
		pjsua_acc_set_online_status2(account, PJ_TRUE, &pr);
		m_isAway = !online;
		UpdateWindowText();
	}
}

LRESULT CmicrosipDlg::onDialNumber(WPARAM wParam,LPARAM lParam)
{
	COPYDATASTRUCT *s = (COPYDATASTRUCT*)lParam;
	if (s)
	{
		BOOL noReg = accountSettings.server=="" || accountSettings.username=="" || accountSettings.domain=="";
		CString params = (LPTSTR)s->lpData;
		params.Trim();
		if (params!="") {
			if (noReg || pjsua_acc_is_valid(account)) {
				DialNumber(params);
			} else {
				dialNumberDelayed = params;
			}

		}
	}
	return 0;
}

void CmicrosipDlg::DialNumber(CString params)
{

	CString number;
	CString message;
	int i = params.Find(" ");
	if (i!=-1) {
		number = params.Mid(0,i);
		message = params.Mid(i+1);
		message.Trim();
	} else {
		number = params;
	}
	number.Trim();
	if (number!="") {
		if (message=="") {
			pageDialer->SetNumber(number);
			pageDialer->OnBnClickedCall();
		} else {
			messagesDlg->SendMessage(NULL, message, number);
		}
	}
}

void CmicrosipDlg::RingIn(CString filename, BOOL noLoop, BOOL inCall)
{
	if (player_id != PJSUA_INVALID_ID && (!beepPlaying || filename != "") ) {
		pjsua_conf_disconnect(pjsua_player_get_conf_port(player_id),0);
		if (pjsua_player_destroy(player_id)==PJ_SUCCESS) {
			player_id = PJSUA_INVALID_ID;
		}
	}
	if (filename != "") {
		beepPlaying = filename == "ringin2.wav";
		pj_str_t file = pj_str(filename.GetBuffer());
		if (pjsua_player_create( &file, noLoop?PJMEDIA_FILE_NO_LOOP:0, &player_id)== PJ_SUCCESS) {
			if (
				(!tone_gen && pjsua_conf_get_active_ports()<=2)
				||
				(tone_gen && pjsua_conf_get_active_ports()<=3)
				) {
					SetSoundDevice(inCall?audio_output:audio_ring);
			}
			pjsua_conf_connect(pjsua_player_get_conf_port(player_id),0);
		}
	}
}

void CmicrosipDlg::SetSoundDevice(int outDev){
	int in,out;
	if (pjsua_get_snd_dev(&in,&out)!=PJ_SUCCESS || audio_input!=in || outDev!=out ) {
		pjsua_set_snd_dev(audio_input, outDev);
	}
}

LRESULT CmicrosipDlg::onCallAnswer(WPARAM wParam,LPARAM lParam)
{
	pjsua_call_id call_id = wParam;
	if (lParam<0) {
		pjsua_call_answer(call_id, -lParam, NULL, NULL);
		return 0;
	}
	if (accountSettings.singleMode) {
		call_hangup_all_noincoming();
	}
	SetSoundDevice(audio_output);
#ifdef _GLOBAL_VIDEO
	if (lParam>0) {
		createPreviewWin();
	}
#endif
	pjsua_call_info call_info;
	pjsua_call_get_info(call_id,&call_info);

	pjsua_call_setting call_setting;
	pjsua_call_setting_default(&call_setting);
	call_setting.vid_cnt=lParam>0 ? 1:0;
	call_setting.flag = 0;
	if (pjsua_call_answer2(call_id, &call_setting, 200, NULL, NULL) == PJ_SUCCESS) {
		callIdImcomingIgnore = PjToStr(&call_info.call_id);
	}
	RingIn();
	onTrayNotify(NULL,WM_LBUTTONUP);
	return 0;
}

LRESULT CmicrosipDlg::onCallHangup(WPARAM wParam,LPARAM lParam)
{
	pjsua_call_id call_id = wParam;
	call_hangup_fast(call_id);
	return 0;
}

LRESULT CmicrosipDlg::onSetPaneText(WPARAM wParam,LPARAM lParam)
{
	CString* pString = (CString*)lParam;
    ASSERT(pString != NULL);
    m_bar.SetPaneText(0, *pString);
    delete pString;
	return 0;
}

BOOL CmicrosipDlg::CopyStringToClipboard( IN const CString & str )
{
	// Open the clipboard
	if ( !OpenClipboard() )
		return FALSE;

	// Empty the clipboard
	if ( !EmptyClipboard() )
	{
		CloseClipboard();
		return FALSE;
	}

	// Number of bytes to copy (consider +1 for end-of-string, and
	// properly scale byte size to sizeof(TCHAR))
	SIZE_T textCopySize = (str.GetLength() + 1) * sizeof(TCHAR);

	// Allocate a global memory object for the text
	HGLOBAL hTextCopy = GlobalAlloc( GMEM_MOVEABLE, textCopySize );
	if ( hTextCopy == NULL )
	{
		CloseClipboard();
		return FALSE;
	}

	// Lock the handle, and copy source text to the buffer
	TCHAR * textCopy = reinterpret_cast< TCHAR *>( GlobalLock(
		hTextCopy ) );
	ASSERT( textCopy != NULL );
	StringCbCopy( textCopy, textCopySize, str.GetString() );
	GlobalUnlock( hTextCopy );
	textCopy = NULL; // avoid dangling references

	// Place the handle on the clipboard
#if defined( _UNICODE )
	UINT textFormat = CF_UNICODETEXT;  // Unicode text
#else
	UINT textFormat = CF_TEXT;         // ANSI text
#endif // defined( _UNICODE )

	if (SetClipboardData( textFormat, hTextCopy ) == NULL )
	{
		// Failed
		CloseClipboard();
		return FALSE;
	}

	// Release the clipboard
	CloseClipboard();

	// All right
	return TRUE;
}

void CmicrosipDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
#ifndef _GLOBAL_EXIT_ON_CLOSE
	if (nID==SC_CLOSE) {
		ShowWindow(SW_HIDE);
	} else {
		__super::OnSysCommand(nID, lParam);
	}
#else
	__super::OnSysCommand(nID, lParam);
#endif
}

BOOL CmicrosipDlg::OnQueryEndSession()
{
	DestroyWindow();
	return TRUE;
}

void CmicrosipDlg::OnClose()
{
	DestroyWindow ();
}

void CmicrosipDlg::OnContextMenu(CWnd *pWnd, CPoint point)
{
	CPoint local = point;
	ScreenToClient(&local);
	CRect rect;
	GetClientRect(&rect);
	if (rect.Height()-local.y <= 16) {
		MainPopupMenu();
	} else {
		DefWindowProc(WM_CONTEXTMENU,NULL,MAKELPARAM(point.x,point.y));
	}
}

void CmicrosipDlg::OnMove(int x, int y)
{
	if (IsWindowVisible() && !IsZoomed() && !IsIconic()) {
		CRect cRect;
		GetWindowRect(&cRect);
		accountSettings.mainX = cRect.left;
		accountSettings.mainY = cRect.top;
		accountSettings.Save();
	}
}

void CmicrosipDlg::OnSize(UINT type, int w, int h)
{
	CBaseDialog::OnSize(type, w, h);
	if (this->IsWindowVisible() && type == SIZE_RESTORED) {
		CRect cRect;
		GetWindowRect(&cRect);
		accountSettings.mainW = cRect.Width();
		accountSettings.mainH = cRect.Height();
		accountSettings.Save();
	}
}

void CmicrosipDlg::SetupJumpList()
{
// CStringW appId(_GLOBAL_NAME);
// JumpList jl(appId.GetBuffer());
// jl.AddTasks();
}

void CmicrosipDlg::RemoveJumpList()
{
// CStringW appId(_GLOBAL_NAME);
// JumpList jl(appId.GetBuffer());
// jl.DeleteJumpList();
}

BOOL CmicrosipDlg::SelectSIPAccount(CString number, pjsua_acc_id &acc_id, pj_str_t &pj_uri)
{
	SIPURI sipuri;
	ParseSIPURI(number, &sipuri);
	bool isLocal = accountSettings.domain=="";
	if (!isLocal) {
		if (accountSettings.domain != sipuri.domain && !accountSettings.disableLocalAccount) {
			int pos = sipuri.domain.Find(":");
			CString domainWithoutPort = RemovePort(sipuri.domain);
			if (IsIP(domainWithoutPort)) {
				isLocal = TRUE;
			}
		}
	}
	acc_id = !isLocal && pjsua_acc_is_valid(account) ? account : NULL;
#ifdef _GLOBAL_NUMBER_PREFIX
	number = _GLOBAL_NUMBER_PREFIX + number;
#endif
	pj_uri = pj_str ( StrToPj ( GetSIPURI(number, accountSettings.domain!=sipuri.domain && accountSettings.domain != "", isLocal) ) );
	return isLocal;
}

void CmicrosipDlg::OnMenuWebsite()
{
#ifndef _GLOBAL_CUSTOM
	OpenURL("http://www.microsip.org/");
#endif
#ifdef _GLOBAL_MENU_WEBSITE
	CString url;
	url.Format(_GLOBAL_MENU_WEBSITE,accountSettings.username);
	OpenURL(url);
#endif
}

void CmicrosipDlg::UsersDirectoryLoad()
{
#ifndef _GLOBAL_NO_CONTACTS
	KillTimer(IDT_TIMER_DIRECTORY);
	if (accountSettings.usersDirectory!="") {
		CString data;
		CInternetSession session;
		int expires = 0;
		try {
			CHttpFile* pFile;
			pFile = (CHttpFile*)session.OpenURL(accountSettings.usersDirectory);
			if (pFile)
			{
				DWORD status;
				pFile->QueryInfoStatusCode(status);
				if (status == 200)
				{
					CString headers;
					pFile->QueryInfo(
						HTTP_QUERY_RAW_HEADERS_CRLF,
						headers
						);
					int i = headers.Find("\r\nCache-Control: max-age=");
					if (i) {
						headers = headers.Mid(i+25);
						expires = atoi(headers);
					}
					pFile->ReadString(data);
					data = Utf8DecodeCP(data.GetBuffer(), CP_ACP, NULL);
				}
				pFile->Close();
			}
			session.Close();
		} catch (CInternetException *e) {
			e;
		}
		if (data!="") {
			CXMLFile xmlFile;
			if ( xmlFile.LoadFromStream((BYTE*)data.GetBuffer(),data.GetLength()) ){
				BOOL ok = FALSE;
				pageContacts->SetCanditates();
				CXMLElement *root = xmlFile.GetRoot();
				CXMLElement *directory = root->GetFirstChild();
				while (directory) {
					if (directory->GetElementType() == XET_TAG) {
						CXMLElement *entry = directory->GetFirstChild();
						while (entry) {
							if (entry->GetElementType() == XET_TAG) {
								CXMLElement *data = entry->GetFirstChild();
								CString number;
								CString name;
								while (data) {
									if (data->GetElementType() == XET_TAG) {
										CString dataName = data->GetElementName();
										CXMLElement *value = data->GetFirstChild();
										if (value->GetElementType() == XET_TEXT) {
											if (dataName == "name" || dataName == "Name") {
												name = value->GetElementName();
											} else if (dataName == "extension" || dataName == "number" || dataName == "Telephone") {
												number = value->GetElementName();
											}
										}
									}
									data = entry->GetNextChild();
								}
								if (number!="") {
									pageContacts->ContactAdd(number, name, TRUE, TRUE, TRUE);
									ok = TRUE;
								}
							}
							entry = directory->GetNextChild();
						}
					}
					directory=root->GetNextChild();
				}
				if (ok) {
					pageContacts->DeleteCanditates();
				}
			}
		}
		if (!expires) {
			expires = 3600;
		} else if (expires<60) {
			expires = 60;
		}
		SetTimer(IDT_TIMER_DIRECTORY,1000*expires,NULL);
	}
#endif
}


#if !defined _GLOBAL_CUSTOM || defined _GLOBAL_UPDATES
void CmicrosipDlg::CheckUpdates()
{
	CInternetSession session;
	try {
		CHttpFile* pFile;
#ifdef _GLOBAL_UPDATES
		CString url;
		url.Format("http://update1.microsip.org/?client=%s&version=",_GLOBAL_UPDATES,_GLOBAL_UPDATES);
#else
		CString url = "http://update.microsip.org/?version=";
#endif
		url.Append(_GLOBAL_VERSION);
#ifndef _GLOBAL_VIDEO
		url.Append("&lite=1");
#endif
		pFile = (CHttpFile*)session.OpenURL(url);
		if (pFile)
		{
			DWORD status;
			pFile->QueryInfoStatusCode(status);
			if (status == 202)
			{
				CString message;
				message.Format("Do you want to update %s?", _GLOBAL_NAME_NICE);
				if (::MessageBox(this->m_hWnd, Translate(message.GetBuffer()), Translate("Update available"), MB_YESNO|MB_ICONQUESTION) == IDYES)
				{
#ifdef _GLOBAL_UPDATES
					pFile->ReadString(url);
					OpenURL(url);
#else
					OpenURL("http://www.microsip.org/downloads");
#endif
				}
			}
			pFile->Close();
		}
		session.Close();
	} catch (CInternetException *e) {
		e;
	}
}
#endif

#ifdef _GLOBAL_VIDEO
int CmicrosipDlg::VideoCaptureDeviceId(CString name)
{
	unsigned count = 64;
	pjmedia_vid_dev_info vid_dev_info[64];
	pjsua_vid_enum_devs(vid_dev_info, &count);
	for (unsigned i=0;i<count;i++)
	{
		if (vid_dev_info[i].fmt_cnt && (vid_dev_info[i].dir==PJMEDIA_DIR_ENCODING || vid_dev_info[i].dir==PJMEDIA_DIR_ENCODING_DECODING))
		{
			if ((name!="" && name ==vid_dev_info[i].name)
				||
				(name=="" && accountSettings.videoCaptureDevice ==vid_dev_info[i].name))
			{
				return vid_dev_info[i].id;
			}
		}
	}
	return PJMEDIA_VID_DEFAULT_CAPTURE_DEV;
}

void CmicrosipDlg::createPreviewWin()
{
	if (!previewWin) {
		previewWin = new Preview(this);
	}
	previewWin->Start(VideoCaptureDeviceId());
}
#endif

#ifdef _GLOBAL_BALANCE_GTN
void CmicrosipDlg::BalanceGTN()
{
	if (pageDialer) {
		try {
			CString data;
			CInternetSession session;
			CHttpConnection* m_pHttp = session.GetHttpConnection(_GLOBAL_BALANCE_GTN_HOST);
			CHttpFile* pFile = m_pHttp->OpenRequest("POST",_GLOBAL_BALANCE_GTN_PATH);
			CString strHeaders="Content-Type: application/x-www-form-urlencoded";
			CString strFormData;
			strFormData.Format("username=%s",accountSettings.password);
			pFile->SendRequest(strHeaders,(LPVOID)strFormData.GetBuffer(),strFormData.GetLength());

			pFile->ReadString(data);

			session.Close();
			m_pHttp->Close();
			pFile->Close();
			CString str = "";
			int i = data.Find("[credit] => ");
			if (i != -1) {
				i+=12;
				int j = data.Find("\n",i);
				if (j != -1) {
					str=data.Mid(i,j-i);
					str.Trim(" \r\n\t");
				}
			}
			i = data.Find("[currency] => ");
			if (i != -1) {
				i+=14;
				int j = data.Find("\n",i);
				if (j != -1) {
					str.AppendFormat(" %s",data.Mid(i,j-i));
					str.Trim(" \r\n\t");
				}
			}
			pageDialer->GetDlgItem(IDC_BALANCE)->SetWindowText( str!="" ? "Balance: " + str : Translate(_GLOBAL_NAME_NICE) );
		}
		catch (CInternetException* pEx) {}
	}
}
#endif

#ifdef _GLOBAL_BALANCE_BEE
void CmicrosipDlg::LoginBEE()
{
	CInternetSession session;
	try {
		CString data;
		CHttpConnection* m_pHttp = session.GetHttpConnection(_GLOBAL_REG_API);
		CHttpFile* pFile = m_pHttp->OpenRequest("POST",_GLOBAL_REG_API_PATH);
		CString strHeaders="Content-Type: application/x-www-form-urlencoded";
		CString strFormData;

		Json::Value root;
		root["act"] = "login";
		root["fields"]["login"] = (LPCSTR) accountSettings.username;
		root["fields"]["password"] = (LPCSTR) accountSettings.password;
		Json::FastWriter writer;
		std::string output = writer.write(root);
		strFormData.Format("jsonData=%s",
			urlencode(output.c_str())
			);

		pFile->SendRequest(strHeaders,(LPVOID)strFormData.GetBuffer(),strFormData.GetLength());
		pFile->ReadString(data);
		pFile->Close();
		m_pHttp->Close();
		session.Close();
		if (data!="") {
			data = Utf8DecodeCP(data.GetBuffer(), CP_ACP, NULL);
			Json::Reader reader;
			bool parsedSuccess = reader.parse((LPCTSTR)data, 
				root, 
				false);
			if(parsedSuccess) {
				try {
					if (root["status"].asString()=="ok") {
						CString userId = root["userId"].asString().c_str();
						regUserId = atoi(userId.GetBuffer());
					}
				} catch (std::exception const& e) {}
			}
		}
	} catch (CInternetException *e) {
	}
	if (!regUserId) {
		regUserId = -1;
	}
}

void CmicrosipDlg::BalanceBEE()
{
	if (pageDialer) {
		if (!regUserId) {
			LoginBEE();
		}
		if (regUserId>0) {
			CInternetSession session;
			try {
				CString data;
				CHttpConnection* m_pHttp = session.GetHttpConnection(_GLOBAL_REG_API);
				CHttpFile* pFile = m_pHttp->OpenRequest("POST",_GLOBAL_REG_API_PATH);
				CString strHeaders="Content-Type: application/x-www-form-urlencoded";
				CString strFormData;

				Json::Value root;
				root["act"] = "balance";
				CString userId;
				userId.Format("%d",regUserId);
				root["fields"]["userId"] = (LPCSTR) userId;
				Json::FastWriter writer;
				std::string output = writer.write(root);
				strFormData.Format("jsonData=%s",
					urlencode(output.c_str())
					);
				pFile->SendRequest(strHeaders,(LPVOID)strFormData.GetBuffer(),strFormData.GetLength());
				pFile->ReadString(data);
				pFile->Close();
				m_pHttp->Close();
				session.Close();
				if (data!="") {
					data = Utf8DecodeCP(data.GetBuffer(), CP_ACP, NULL);
					Json::Reader reader;
					bool parsedSuccess = reader.parse((LPCTSTR)data, 
						root, 
						false);
					if(parsedSuccess) {
						try {
							if (root["status"].asString()=="ok") {
								CString str;
								if (root["text"].asString()!="") {
									str.Format("%s: %s",Translate(_T("Balance")),root["text"].asString().c_str());
								} else {
									str = Translate(_GLOBAL_NAME_NICE);
								}
								pageDialer->GetDlgItem(IDC_BALANCE)->SetWindowText( str );
							}
						} catch (std::exception const& e) {}
					}
				}

			} catch (CInternetException *e) {
			}
		}
	}
}
#endif

#ifdef _GLOBAL_BALANCE_PLAIN
void CmicrosipDlg::BalancePlain()
{
	if (pageDialer) {
		try {
			CString data;
			CInternetSession session;
			CString url;
			url.Format(_GLOBAL_BALANCE_URL,accountSettings.username,accountSettings.password);
			CHttpFile* pFile = (CHttpFile*)session.OpenURL(url);
			if (pFile) {
				DWORD status;
				pFile->QueryInfoStatusCode(status);
				if (status == 200)
				{
					CString buf;
					while (pFile->ReadString(buf)) {
						data.Append(buf);
					}
				}
				pFile->Close();
			}
			session.Close();
			data.Trim();
			if (data!="") {
				CString balance;
#if _GLOBAL_BALANCE_PLAIN == x53101D78
				CXMLFile xmlFile;
				if ( xmlFile.LoadFromStream((BYTE*)data.GetBuffer(),data.GetLength()) ){
					CXMLElement *root = xmlFile.GetRoot();
					CXMLElement *directory = root->GetFirstChild();
					while (directory) {
						if (directory->GetElementType() == XET_TAG) {
							CXMLElement *entry = directory->GetFirstChild();
							while (entry) {
								if (entry->GetElementType() == XET_TAG) {
									if (strcmp(entry->GetElementName(),"credit")==0) {
										CXMLElement *value = entry->GetFirstChild();
										balance = value->GetElementName();
									}
								}
								entry = directory->GetNextChild();
							}
						}
						directory=root->GetNextChild();
					}
				}
#else
				balance = data;
#endif
				if (balance!="") {
					CString str;
					str.Format("%s: %s",Translate(_T("Balance")),balance);
					if (microsipDlg->pageDialer) {
						microsipDlg->pageDialer->GetDlgItem(IDC_BALANCE)->SetWindowText( str );
					}
				}
			}
		}
		catch (CInternetException* pEx) {}
	}
}
#endif

#ifdef _GLOBAL_BALANCE_OPTIONS
void cb_balance_options(void *token, pjsip_event *e)
{
	if (e->body.rx_msg.rdata->tp_info.op_key.rdata->msg_info.msg->line.status.code == 200) {
		CString balance = PjToStr(&e->body.rx_msg.rdata->tp_info.op_key.rdata->msg_info.msg->line.status.reason);
		balance.Trim();
		if (balance.GetLength()) {
			CString str;
			str.Format("%s: %s",Translate(_T("Balance")),balance);
			if (microsipDlg->pageDialer) {
				microsipDlg->pageDialer->GetDlgItem(IDC_BALANCE)->SetWindowText( str );
			}
		}
	}
}
void CmicrosipDlg::BalanceOption()
{
	pj_str_t dst_uri = pj_str ( StrToPj ( microsipDlg->GetSIPURI(_GLOBAL_BALANCE_OPTIONS) ) );
	pjsip_method method;
	pjsip_tx_data *tdata;
	pjsip_endpoint *endpt;
	pj_status_t status;

	endpt = pjsua_get_pjsip_endpt();

	pjsip_method_set(&method, PJSIP_OPTIONS_METHOD);

	status = pjsua_acc_create_request(pjsua_acc_is_valid(microsipDlg->account) ? microsipDlg->account : NULL, &method, &dst_uri, &tdata);
	if (status != PJ_SUCCESS) {
		pjsua_perror(THIS_FILE, "pjsua_acc_create_request failed", status);
		return;
	}
	status = pjsip_endpt_send_request(endpt, tdata, -1, NULL, cb_balance_options);
	if (status != PJ_SUCCESS) {
		pjsua_perror(THIS_FILE, "pjsip_endpt_send_request failed", status);
		return;
	}
}
#endif